Laying the groundwork for interactive reporting & dashboards…
- ggplot2 and gridExtra
library(ggplot2)
library(gridExtra)
data(anscombe)
sapply(1:4, function(x) cor(anscombe[, x], anscombe[, x+4]))
[1] 0.8164205 0.8162365 0.8162867 0.8165214
sapply(5:8, function(x) var(anscombe[, x]))
[1] 4.127269 4.127629 4.122620 4.123249
lm(y1 ~ x1, data = anscombe)
Call:
lm(formula = y1 ~ x1, data = anscombe)
Coefficients:
(Intercept) x1
3.0001 0.5001
p1 <- ggplot(anscombe) + geom_point(aes(x1, y1), color = "darkorange", size = 3) + theme_bw() + scale_x_continuous(breaks = seq(0, 20, 2)) + scale_y_continuous(breaks = seq(0, 12, 2)) + geom_abline(intercept = 3, slope = 0.5, color = "cornflowerblue") + expand_limits(x = 0, y = 0) + labs(title = "dataset 1")
p2 <- ggplot(anscombe) + geom_point(aes(x2, y2), color = "darkorange", size = 3) + theme_bw() + scale_x_continuous(breaks = seq(0, 20, 2)) + scale_y_continuous(breaks = seq(0, 12, 2)) + geom_abline(intercept = 3, slope = 0.5, color = "cornflowerblue") + expand_limits(x = 0, y = 0) + labs(title = "dataset 2")
p3 <- ggplot(anscombe) + geom_point(aes(x3, y3), color = "darkorange", size = 3) + theme_bw() + scale_x_continuous(breaks = seq(0, 20, 2)) + scale_y_continuous(breaks = seq(0, 12, 2)) + geom_abline(intercept = 3, slope = 0.5, color = "cornflowerblue") + expand_limits(x = 0, y = 0) + labs(title = "dataset 3")
p4 <- ggplot(anscombe) + geom_point(aes(x4, y4), color = "darkorange", size = 3) + theme_bw() + scale_x_continuous(breaks = seq(0, 20, 2)) + scale_y_continuous(breaks = seq(0, 12, 2)) + geom_abline(intercept = 3, slope = 0.5, color = "cornflowerblue") + expand_limits(x = 0, y = 0) + labs(title = "dataset 4")
grid.arrange(p1, p2, p3, p4, top = "Anscombe's Quartet")

- HTML Widgets
http://www.htmlwidgets.org
2.A Dygraphs
http://www.htmlwidgets.org/showcase_dygraphs.html
Basic plot example:
## standard graphics device
library(stats)
plot(nhtemp, main = "nhtemp data", ylab = "Mean annual temp. in F)")

## using dygraphs
library(dygraphs)
fig <- dygraph(nhtemp, main = "New Haven Temperatures")
fig <- dyAxis(fig, "y", label = "Temp (F)", valueRange = c(40, 60))
fig <- dyOptions(fig, axisLineWidth = 1.5, fillGraph = TRUE, drawGrid = FALSE)
fig
dygraph(nhtemp, main = "New Haven Temperatures") %>%
dySeries("V1", label = "Temperature (F)") %>%
dyLegend(show = "always", hideOnMouseOut = FALSE)
dygraph(nhtemp, main = "New Haven Temperatures") %>%
dyRangeSelector()
dygraph(nhtemp, main = "New Haven Temperatures") %>%
dyRangeSelector(dateWindow = c("1920-01-01", "1960-01-01"))
dygraph(nhtemp, main = "New Haven Temperatures") %>%
dyRangeSelector(height = 20, strokeColor = "")
#Shaded Regions
dygraph(nhtemp, main = "New Haven Temperatures") %>%
dyShading(from = "1920-1-1", to = "1930-1-1") %>%
dyShading(from = "1940-1-1", to = "1950-1-1")
dygraph(nhtemp, main = "New Haven Temperatures") %>%
dySeries(label = "Temp (F)", color = "black") %>%
dyShading(from = "1920-1-1", to = "1930-1-1", color = "#FFE6E6") %>%
dyShading(from = "1940-1-1", to = "1950-1-1", color = "#CCEBD6")
library(quantmod)
library(dygraphs)
library(quantmod)
getSymbols("MSFT", src = "google", from = "2014-06-01", auto.assign=TRUE)
[1] "MSFT"
ret = ROC(MSFT[, 4])
mn = mean(ret, na.rm = TRUE)
std = sd(ret, na.rm = TRUE)
dygraph(ret, main = "Microsoft Share Price") %>%
dySeries("MSFT.Close", label = "MSFT") %>%
dyShading(from = mn - std, to = mn + std, axis = "y")
getSymbols("MSFT", src = "google", from = "2014-06-01", auto.assign=TRUE)
[1] "MSFT"
dygraph(MSFT[, 4], main = "Microsoft Share Price") %>%
dySeries("MSFT.Close", label = "MSFT") %>%
dyLimit(as.numeric(MSFT[1, 4]), color = "red")
getSymbols(c("MSFT", "HPQ"), src = "google", from = "2014-06-01", auto.assign=TRUE)
[1] "MSFT" "HPQ"
stocks <- cbind(MSFT[,2:4], HPQ[,2:4])
dygraph(stocks, main = "Microsoft and HP Share Prices") %>%
dySeries(c("MSFT.Low", "MSFT.Close", "MSFT.High"), label = "MSFT") %>%
dySeries(c("HPQ.Low", "HPQ.Close", "HPQ.High"), label = "HPQ")
2.B Plotly
http://www.htmlwidgets.org/showcase_plotly.html
https://plot.ly/r/dashboard/
https://plot.ly/r/shiny-tutorial/
library(ggplot2)
library(plotly)
p <- ggplot(data = diamonds, aes(x = cut, fill = clarity)) +
geom_bar(position = "dodge")
ggplotly(p)
d <- diamonds[sample(nrow(diamonds), 500), ]
plot_ly(d, x = d$carat, y = d$price,
text = paste("Clarity: ", d$clarity),
mode = "markers", color = d$carat, size = d$carat)
No trace type specified:
Based on info supplied, a 'scatter' trace seems appropriate.
Read more about this trace type -> https://plot.ly/r/reference/#scatter
No trace type specified:
Based on info supplied, a 'scatter' trace seems appropriate.
Read more about this trace type -> https://plot.ly/r/reference/#scatter
2.C rbokeh
http://www.htmlwidgets.org/showcase_rbokeh.html
library(rbokeh)
figure() %>%
ly_points(Sepal.Length, Sepal.Width, data = iris,
color = Species, glyph = Species,
hover = list(Sepal.Length, Sepal.Width))
figure(width = NULL, height = NULL, legend_location = "top_left") %>%
ly_quantile(Sepal.Length, group = Species, data = iris)
figure(width = NULL, height = NULL) %>%
ly_points(Sepal.Length, Sepal.Width, data = iris,
color = Petal.Width)
tools <- c("pan", "wheel_zoom", "box_zoom", "box_select", "reset")
nms <- expand.grid(names(iris)[1:4], rev(names(iris)[1:4]), stringsAsFactors = FALSE)
splom_list <- vector("list", 16)
for(ii in seq_len(nrow(nms))) {
splom_list[[ii]] <- figure(width = 200, height = 200, tools = tools,
xlab = nms$Var1[ii], ylab = nms$Var2[ii]) %>%
ly_points(nms$Var1[ii], nms$Var2[ii], data = iris,
color = Species, size = 5, legend = FALSE)
}
grid_plot(splom_list, ncol = 4, same_axes = TRUE, link_data = TRUE)
2.4 DT
http://www.htmlwidgets.org/showcase_datatables.html
library(DT)
datatable(iris, options = list(pageLength = 5))
- Interactive Plots - Shiny
http://shiny.rstudio.com/gallery/
Exmaples:
3_Shiny_Basic_Plots
3_Shiny_ToothGrowth_Plots
- shinydashboard
https://rstudio.github.io/shinydashboard/
Examples:
4_Shiny_stockVis_basic
4_Shiny_stockapp_tabs
4_Shiny_shinydashboard_basic
4_Shiny_shinydashboard_box
- flexdashboard
http://rmarkdown.rstudio.com/flexdashboard/examples.html
Examples:
5_RMD_Flex_RMD_To_Shiny_Intro
5_RMD_Flex_ToothGrowth
5_RMD_Flex_Shiny_ToothGrowth
- Crosstalk
http://rstudio.github.io/crosstalk/index.html
http://rstudio.github.io/crosstalk/shiny.html
Examples:
6_Crosstalk_Shiny
- HTML Templates
https://shiny.rstudio.com/articles/templates.html
https://github.com/nwstephens/nyr2016
Examples:
7_Shiny_htmlTemplates
LS0tCnRpdGxlOiAiSW50ZXJhY3RpdmUgUmVwb3J0aW5nIERhc2hib2FyZHMgaW4gU2hpbnkiCm91dHB1dDoKICBodG1sX25vdGVib29rOiBkZWZhdWx0CiAgaHRtbF9kb2N1bWVudDogZGVmYXVsdAotLS0KCkxheWluZyB0aGUgZ3JvdW5kd29yayBmb3IgaW50ZXJhY3RpdmUgcmVwb3J0aW5nICYgZGFzaGJvYXJkcy4uLgoKMS4gZ2dwbG90MiBhbmQgZ3JpZEV4dHJhCgpgYGB7cn0KbGlicmFyeShnZ3Bsb3QyKQpsaWJyYXJ5KGdyaWRFeHRyYSkKCmRhdGEoYW5zY29tYmUpCgpzYXBwbHkoMTo0LCBmdW5jdGlvbih4KSBjb3IoYW5zY29tYmVbLCB4XSwgYW5zY29tYmVbLCB4KzRdKSkKc2FwcGx5KDU6OCwgZnVuY3Rpb24oeCkgdmFyKGFuc2NvbWJlWywgeF0pKQpsbSh5MSB+IHgxLCBkYXRhID0gYW5zY29tYmUpCgpwMSA8LSBnZ3Bsb3QoYW5zY29tYmUpICsgZ2VvbV9wb2ludChhZXMoeDEsIHkxKSwgY29sb3IgPSAiZGFya29yYW5nZSIsIHNpemUgPSAzKSArIHRoZW1lX2J3KCkgKyBzY2FsZV94X2NvbnRpbnVvdXMoYnJlYWtzID0gc2VxKDAsIDIwLCAyKSkgKyBzY2FsZV95X2NvbnRpbnVvdXMoYnJlYWtzID0gc2VxKDAsIDEyLCAyKSkgKyBnZW9tX2FibGluZShpbnRlcmNlcHQgPSAzLCBzbG9wZSA9IDAuNSwgY29sb3IgPSAiY29ybmZsb3dlcmJsdWUiKSArIGV4cGFuZF9saW1pdHMoeCA9IDAsIHkgPSAwKSArIGxhYnModGl0bGUgPSAiZGF0YXNldCAxIikKcDIgPC0gZ2dwbG90KGFuc2NvbWJlKSArIGdlb21fcG9pbnQoYWVzKHgyLCB5MiksIGNvbG9yID0gImRhcmtvcmFuZ2UiLCBzaXplID0gMykgKyB0aGVtZV9idygpICsgc2NhbGVfeF9jb250aW51b3VzKGJyZWFrcyA9IHNlcSgwLCAyMCwgMikpICsgc2NhbGVfeV9jb250aW51b3VzKGJyZWFrcyA9IHNlcSgwLCAxMiwgMikpICsgZ2VvbV9hYmxpbmUoaW50ZXJjZXB0ID0gMywgc2xvcGUgPSAwLjUsIGNvbG9yID0gImNvcm5mbG93ZXJibHVlIikgKyBleHBhbmRfbGltaXRzKHggPSAwLCB5ID0gMCkgKyBsYWJzKHRpdGxlID0gImRhdGFzZXQgMiIpCnAzIDwtIGdncGxvdChhbnNjb21iZSkgKyBnZW9tX3BvaW50KGFlcyh4MywgeTMpLCBjb2xvciA9ICJkYXJrb3JhbmdlIiwgc2l6ZSA9IDMpICsgdGhlbWVfYncoKSArIHNjYWxlX3hfY29udGludW91cyhicmVha3MgPSBzZXEoMCwgMjAsIDIpKSArIHNjYWxlX3lfY29udGludW91cyhicmVha3MgPSBzZXEoMCwgMTIsIDIpKSArIGdlb21fYWJsaW5lKGludGVyY2VwdCA9IDMsIHNsb3BlID0gMC41LCBjb2xvciA9ICJjb3JuZmxvd2VyYmx1ZSIpICsgZXhwYW5kX2xpbWl0cyh4ID0gMCwgeSA9IDApICsgbGFicyh0aXRsZSA9ICJkYXRhc2V0IDMiKQpwNCA8LSBnZ3Bsb3QoYW5zY29tYmUpICsgZ2VvbV9wb2ludChhZXMoeDQsIHk0KSwgY29sb3IgPSAiZGFya29yYW5nZSIsIHNpemUgPSAzKSArIHRoZW1lX2J3KCkgKyBzY2FsZV94X2NvbnRpbnVvdXMoYnJlYWtzID0gc2VxKDAsIDIwLCAyKSkgKyBzY2FsZV95X2NvbnRpbnVvdXMoYnJlYWtzID0gc2VxKDAsIDEyLCAyKSkgKyBnZW9tX2FibGluZShpbnRlcmNlcHQgPSAzLCBzbG9wZSA9IDAuNSwgY29sb3IgPSAiY29ybmZsb3dlcmJsdWUiKSArIGV4cGFuZF9saW1pdHMoeCA9IDAsIHkgPSAwKSArIGxhYnModGl0bGUgPSAiZGF0YXNldCA0IikKCmdyaWQuYXJyYW5nZShwMSwgcDIsIHAzLCBwNCwgdG9wID0gIkFuc2NvbWJlJ3MgUXVhcnRldCIpCmBgYAoKMi4gSFRNTCBXaWRnZXRzCgpodHRwOi8vd3d3Lmh0bWx3aWRnZXRzLm9yZwoKMi5BIER5Z3JhcGhzCgpodHRwOi8vd3d3Lmh0bWx3aWRnZXRzLm9yZy9zaG93Y2FzZV9keWdyYXBocy5odG1sCgpCYXNpYyBwbG90IGV4YW1wbGU6CgpgYGB7cn0KIyMgc3RhbmRhcmQgZ3JhcGhpY3MgZGV2aWNlCmxpYnJhcnkoc3RhdHMpCnBsb3Qobmh0ZW1wLCBtYWluID0gIm5odGVtcCBkYXRhIiwgeWxhYiA9ICJNZWFuIGFubnVhbCB0ZW1wLiBpbiBGKSIpCgpgYGAKCgpgYGB7cn0KIyMgdXNpbmcgZHlncmFwaHMKbGlicmFyeShkeWdyYXBocykKZmlnIDwtIGR5Z3JhcGgobmh0ZW1wLCBtYWluID0gIk5ldyBIYXZlbiBUZW1wZXJhdHVyZXMiKQpmaWcgPC0gZHlBeGlzKGZpZywgInkiLCBsYWJlbCA9ICJUZW1wIChGKSIsIHZhbHVlUmFuZ2UgPSBjKDQwLCA2MCkpCmZpZyA8LSBkeU9wdGlvbnMoZmlnLCBheGlzTGluZVdpZHRoID0gMS41LCBmaWxsR3JhcGggPSBUUlVFLCBkcmF3R3JpZCA9IEZBTFNFKQpmaWcKYGBgCgpgYGB7cn0KZHlncmFwaChuaHRlbXAsIG1haW4gPSAiTmV3IEhhdmVuIFRlbXBlcmF0dXJlcyIpICU+JSAKICBkeVNlcmllcygiVjEiLCBsYWJlbCA9ICJUZW1wZXJhdHVyZSAoRikiKSAlPiUKICBkeUxlZ2VuZChzaG93ID0gImFsd2F5cyIsIGhpZGVPbk1vdXNlT3V0ID0gRkFMU0UpCgpgYGAKCmBgYHtyfQpkeWdyYXBoKG5odGVtcCwgbWFpbiA9ICJOZXcgSGF2ZW4gVGVtcGVyYXR1cmVzIikgJT4lIAogIGR5UmFuZ2VTZWxlY3RvcigpCmBgYAoKYGBge3J9CmR5Z3JhcGgobmh0ZW1wLCBtYWluID0gIk5ldyBIYXZlbiBUZW1wZXJhdHVyZXMiKSAlPiUgCiAgZHlSYW5nZVNlbGVjdG9yKGRhdGVXaW5kb3cgPSBjKCIxOTIwLTAxLTAxIiwgIjE5NjAtMDEtMDEiKSkKYGBgCgpgYGB7cn0KZHlncmFwaChuaHRlbXAsIG1haW4gPSAiTmV3IEhhdmVuIFRlbXBlcmF0dXJlcyIpICU+JSAKICBkeVJhbmdlU2VsZWN0b3IoaGVpZ2h0ID0gMjAsIHN0cm9rZUNvbG9yID0gIiIpCmBgYAoKYGBge3J9CiNTaGFkZWQgUmVnaW9ucwpkeWdyYXBoKG5odGVtcCwgbWFpbiA9ICJOZXcgSGF2ZW4gVGVtcGVyYXR1cmVzIikgJT4lIAogIGR5U2hhZGluZyhmcm9tID0gIjE5MjAtMS0xIiwgdG8gPSAiMTkzMC0xLTEiKSAlPiUKICBkeVNoYWRpbmcoZnJvbSA9ICIxOTQwLTEtMSIsIHRvID0gIjE5NTAtMS0xIikKYGBgCgpgYGB7cn0KZHlncmFwaChuaHRlbXAsIG1haW4gPSAiTmV3IEhhdmVuIFRlbXBlcmF0dXJlcyIpICU+JSAKICBkeVNlcmllcyhsYWJlbCA9ICJUZW1wIChGKSIsIGNvbG9yID0gImJsYWNrIikgJT4lCiAgZHlTaGFkaW5nKGZyb20gPSAiMTkyMC0xLTEiLCB0byA9ICIxOTMwLTEtMSIsIGNvbG9yID0gIiNGRkU2RTYiKSAlPiUKICBkeVNoYWRpbmcoZnJvbSA9ICIxOTQwLTEtMSIsIHRvID0gIjE5NTAtMS0xIiwgY29sb3IgPSAiI0NDRUJENiIpCmBgYAoKYGBge3J9CmxpYnJhcnkocXVhbnRtb2QpCmxpYnJhcnkoZHlncmFwaHMpCgpsaWJyYXJ5KHF1YW50bW9kKQoKZ2V0U3ltYm9scygiTVNGVCIsIHNyYyA9ICJnb29nbGUiLCBmcm9tID0gIjIwMTQtMDYtMDEiLCBhdXRvLmFzc2lnbj1UUlVFKQoKcmV0ID0gUk9DKE1TRlRbLCA0XSkKbW4gPSBtZWFuKHJldCwgbmEucm0gPSBUUlVFKQpzdGQgPSBzZChyZXQsIG5hLnJtID0gVFJVRSkKZHlncmFwaChyZXQsIG1haW4gPSAiTWljcm9zb2Z0IFNoYXJlIFByaWNlIikgJT4lIAogIGR5U2VyaWVzKCJNU0ZULkNsb3NlIiwgbGFiZWwgPSAiTVNGVCIpICU+JQogIGR5U2hhZGluZyhmcm9tID0gbW4gLSBzdGQsIHRvID0gbW4gKyBzdGQsIGF4aXMgPSAieSIpCgoKYGBgCmBgYHtyfQpnZXRTeW1ib2xzKCJNU0ZUIiwgc3JjID0gImdvb2dsZSIsIGZyb20gPSAiMjAxNC0wNi0wMSIsIGF1dG8uYXNzaWduPVRSVUUpCmR5Z3JhcGgoTVNGVFssIDRdLCBtYWluID0gIk1pY3Jvc29mdCBTaGFyZSBQcmljZSIpICU+JSAKICBkeVNlcmllcygiTVNGVC5DbG9zZSIsIGxhYmVsID0gIk1TRlQiKSAlPiUKICBkeUxpbWl0KGFzLm51bWVyaWMoTVNGVFsxLCA0XSksIGNvbG9yID0gInJlZCIpCmBgYAoKYGBge3J9CmdldFN5bWJvbHMoYygiTVNGVCIsICJIUFEiKSwgc3JjID0gImdvb2dsZSIsIGZyb20gPSAiMjAxNC0wNi0wMSIsIGF1dG8uYXNzaWduPVRSVUUpCgpzdG9ja3MgPC0gY2JpbmQoTVNGVFssMjo0XSwgSFBRWywyOjRdKQpkeWdyYXBoKHN0b2NrcywgbWFpbiA9ICJNaWNyb3NvZnQgYW5kIEhQIFNoYXJlIFByaWNlcyIpICU+JSAKICBkeVNlcmllcyhjKCJNU0ZULkxvdyIsICJNU0ZULkNsb3NlIiwgIk1TRlQuSGlnaCIpLCBsYWJlbCA9ICJNU0ZUIikgJT4lCiAgZHlTZXJpZXMoYygiSFBRLkxvdyIsICJIUFEuQ2xvc2UiLCAiSFBRLkhpZ2giKSwgbGFiZWwgPSAiSFBRIikKYGBgCgoKMi5CIFBsb3RseQoKaHR0cDovL3d3dy5odG1sd2lkZ2V0cy5vcmcvc2hvd2Nhc2VfcGxvdGx5Lmh0bWwKCmh0dHBzOi8vcGxvdC5seS9yL2Rhc2hib2FyZC8KCmh0dHBzOi8vcGxvdC5seS9yL3NoaW55LXR1dG9yaWFsLwoKYGBge3J9CmxpYnJhcnkoZ2dwbG90MikKbGlicmFyeShwbG90bHkpCnAgPC0gZ2dwbG90KGRhdGEgPSBkaWFtb25kcywgYWVzKHggPSBjdXQsIGZpbGwgPSBjbGFyaXR5KSkgKwogICAgICAgICAgICBnZW9tX2Jhcihwb3NpdGlvbiA9ICJkb2RnZSIpCmdncGxvdGx5KHApCmBgYAoKYGBge3J9CmQgPC0gZGlhbW9uZHNbc2FtcGxlKG5yb3coZGlhbW9uZHMpLCA1MDApLCBdCnBsb3RfbHkoZCwgeCA9IGQkY2FyYXQsIHkgPSBkJHByaWNlLCAKICAgICAgICB0ZXh0ID0gcGFzdGUoIkNsYXJpdHk6ICIsIGQkY2xhcml0eSksCiAgICAgICAgbW9kZSA9ICJtYXJrZXJzIiwgY29sb3IgPSBkJGNhcmF0LCBzaXplID0gZCRjYXJhdCkKYGBgCgoyLkMgcmJva2VoCgpodHRwOi8vd3d3Lmh0bWx3aWRnZXRzLm9yZy9zaG93Y2FzZV9yYm9rZWguaHRtbAoKYGBge3J9CmxpYnJhcnkocmJva2VoKQpmaWd1cmUoKSAlPiUKICBseV9wb2ludHMoU2VwYWwuTGVuZ3RoLCBTZXBhbC5XaWR0aCwgZGF0YSA9IGlyaXMsCiAgICBjb2xvciA9IFNwZWNpZXMsIGdseXBoID0gU3BlY2llcywKICAgIGhvdmVyID0gbGlzdChTZXBhbC5MZW5ndGgsIFNlcGFsLldpZHRoKSkKYGBgCgpgYGB7cn0KZmlndXJlKHdpZHRoID0gTlVMTCwgaGVpZ2h0ID0gTlVMTCwgbGVnZW5kX2xvY2F0aW9uID0gInRvcF9sZWZ0IikgJT4lCiAgbHlfcXVhbnRpbGUoU2VwYWwuTGVuZ3RoLCBncm91cCA9IFNwZWNpZXMsIGRhdGEgPSBpcmlzKQpgYGAKCgpgYGB7cn0KZmlndXJlKHdpZHRoID0gTlVMTCwgaGVpZ2h0ID0gTlVMTCkgJT4lCiAgbHlfcG9pbnRzKFNlcGFsLkxlbmd0aCwgU2VwYWwuV2lkdGgsIGRhdGEgPSBpcmlzLAogICAgY29sb3IgPSBQZXRhbC5XaWR0aCkKYGBgCgpgYGB7cn0KdG9vbHMgPC0gYygicGFuIiwgIndoZWVsX3pvb20iLCAiYm94X3pvb20iLCAiYm94X3NlbGVjdCIsICJyZXNldCIpCm5tcyA8LSBleHBhbmQuZ3JpZChuYW1lcyhpcmlzKVsxOjRdLCByZXYobmFtZXMoaXJpcylbMTo0XSksIHN0cmluZ3NBc0ZhY3RvcnMgPSBGQUxTRSkKc3Bsb21fbGlzdCA8LSB2ZWN0b3IoImxpc3QiLCAxNikKZm9yKGlpIGluIHNlcV9sZW4obnJvdyhubXMpKSkgewogIHNwbG9tX2xpc3RbW2lpXV0gPC0gZmlndXJlKHdpZHRoID0gMjAwLCBoZWlnaHQgPSAyMDAsIHRvb2xzID0gdG9vbHMsCiAgICB4bGFiID0gbm1zJFZhcjFbaWldLCB5bGFiID0gbm1zJFZhcjJbaWldKSAlPiUKICAgIGx5X3BvaW50cyhubXMkVmFyMVtpaV0sIG5tcyRWYXIyW2lpXSwgZGF0YSA9IGlyaXMsCiAgICAgIGNvbG9yID0gU3BlY2llcywgc2l6ZSA9IDUsIGxlZ2VuZCA9IEZBTFNFKQp9CmdyaWRfcGxvdChzcGxvbV9saXN0LCBuY29sID0gNCwgc2FtZV9heGVzID0gVFJVRSwgbGlua19kYXRhID0gVFJVRSkKYGBgCgoyLjQgRFQKCmh0dHA6Ly93d3cuaHRtbHdpZGdldHMub3JnL3Nob3djYXNlX2RhdGF0YWJsZXMuaHRtbAoKYGBge3J9CmxpYnJhcnkoRFQpCmRhdGF0YWJsZShpcmlzLCBvcHRpb25zID0gbGlzdChwYWdlTGVuZ3RoID0gNSkpCmBgYAoKCjMuIEludGVyYWN0aXZlIFBsb3RzIC0gU2hpbnkKCmh0dHA6Ly9zaGlueS5yc3R1ZGlvLmNvbS9nYWxsZXJ5LwoKRXhtYXBsZXM6CgozX1NoaW55X0Jhc2ljX1Bsb3RzCgozX1NoaW55X1Rvb3RoR3Jvd3RoX1Bsb3RzCgo0LiBzaGlueWRhc2hib2FyZAoKaHR0cHM6Ly9yc3R1ZGlvLmdpdGh1Yi5pby9zaGlueWRhc2hib2FyZC8KCkV4YW1wbGVzOgoKNF9TaGlueV9zdG9ja1Zpc19iYXNpYwoKNF9TaGlueV9zdG9ja2FwcF90YWJzCgo0X1NoaW55X3NoaW55ZGFzaGJvYXJkX2Jhc2ljCgo0X1NoaW55X3NoaW55ZGFzaGJvYXJkX2JveAoKNS4gZmxleGRhc2hib2FyZAoKaHR0cDovL3JtYXJrZG93bi5yc3R1ZGlvLmNvbS9mbGV4ZGFzaGJvYXJkL2V4YW1wbGVzLmh0bWwKCkV4YW1wbGVzOgoKNV9STURfRmxleF9STURfVG9fU2hpbnlfSW50cm8KCjVfUk1EX0ZsZXhfVG9vdGhHcm93dGgKCjVfUk1EX0ZsZXhfU2hpbnlfVG9vdGhHcm93dGgKCjYuIENyb3NzdGFsawoKaHR0cDovL3JzdHVkaW8uZ2l0aHViLmlvL2Nyb3NzdGFsay9pbmRleC5odG1sCgpodHRwOi8vcnN0dWRpby5naXRodWIuaW8vY3Jvc3N0YWxrL3NoaW55Lmh0bWwKCkV4YW1wbGVzOgoKNl9Dcm9zc3RhbGtfU2hpbnkKCjcuIEhUTUwgVGVtcGxhdGVzCgpodHRwczovL3NoaW55LnJzdHVkaW8uY29tL2FydGljbGVzL3RlbXBsYXRlcy5odG1sCgpodHRwczovL2dpdGh1Yi5jb20vbndzdGVwaGVucy9ueXIyMDE2CgpFeGFtcGxlczoKCjdfU2hpbnlfaHRtbFRlbXBsYXRlcwo=